package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIOTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.DeviceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class DeviceServiceImpl implements DeviceService {

    @Autowired
    private Client client;

    @Autowired
    private AliIOTConfigProperties aliIOTConfigProperties;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private DeviceMapper deviceMapper;

    @Override
    public void syncProductList() {
        QueryProductListRequest request = new QueryProductListRequest();
        request.setIotInstanceId(aliIOTConfigProperties.getIotInstanceId());
        request.setCurrentPage(1);
        request.setPageSize(200);
        QueryProductListResponse response;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_PRODUCT_ERROR);
        }
        if (response.body.success) {
            List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo> productInfo =
                    response.body.data.list.productInfo;
            String s = JSONUtil.toJsonStr(productInfo);
            redisTemplate.opsForValue().set(CacheConstants.IOT_PRODUCT_LIST_ALL_PRODUCT, s);
        } else {
            throw new RuntimeException(response.body.errorMessage);
        }
    }

    @Override
    public List<DeviceVo> getAllProduct() {
        String s = redisTemplate.opsForValue().get(CacheConstants.IOT_PRODUCT_LIST_ALL_PRODUCT);
        if (s != null && s.length() != 0) {
            List<DeviceVo> list = JSONUtil.toList(s, DeviceVo.class);
            return list;
        }
        return null;
    }

    @Override
    @Transactional
    public void registerDevice(DeviceDto deviceDto) {
        Integer count = deviceMapper.countDeviceByDeviceName(deviceDto.getDeviceName());
        if(count>0){
            throw new BaseException(BasicEnum.LOCATION_BINDING_PRODUCT);
        }

        //开始新增设备
        RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
        request.iotInstanceId = aliIOTConfigProperties.getIotInstanceId();
        RegisterDeviceResponse response;
        try {
            response = client.registerDevice(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_REGISTER_DEVICE_ERROR);
        }

        if(!response.body.success){
            throw new RuntimeException(response.body.errorMessage);
        }

        //从redis缓存中获取产品名称
        String s = redisTemplate.opsForValue().get(CacheConstants.IOT_PRODUCT_LIST_ALL_PRODUCT);
        if (s != null && s.length() != 0) {
            List<DeviceVo> list = JSONUtil.toList(s, DeviceVo.class);
            list.forEach(deviceVo -> {
                if(deviceVo.getProductKey().equals(deviceDto.productKey)){
                    deviceDto.setProductName(deviceVo.productName);
                }
            });
        }

        //判断位置类型是否为0
        if(deviceDto.getLocationType()==0){
            deviceDto.setPhysicalLocationType(-1);
        }

        //完善新注册设备数据
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        device.setProductName(deviceDto.getProductName());
        device.setIotId(response.body.data.iotId);

        //新增入数据库
        try {
            deviceMapper.insertSelective(device);
        } catch (Exception e) {
            //新增失败
            DeleteDeviceResponse deleteDevice;
            DeleteDeviceRequest deviceRequest = new DeleteDeviceRequest();
            deviceRequest.deviceName = device.getDeviceName();
            deviceRequest.iotId = device.getIotId();
            deviceRequest.iotInstanceId = aliIOTConfigProperties.getIotInstanceId();
            deviceRequest.productKey = device.getProductKey();
            try {
                deleteDevice = client.deleteDevice(deviceRequest);
            } catch (Exception ex) {
                throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
            }

            if(!deleteDevice.body.success){
                throw new RuntimeException(deleteDevice.body.errorMessage);
            }
            throw new BaseException(BasicEnum.RE_SELECT_PRODUCT);
        }
    }

    @Override
    public PageResponse<DeviceVo> selectDeviceByPage(DevicePageQueryDto devicePageQueryDto) {
        PageHelper.startPage(devicePageQueryDto.getPageNum(),devicePageQueryDto.getPageSize());
        Page page = (Page)deviceMapper.selectDeviceByPage(devicePageQueryDto);
        PageResponse<DeviceVo> of = PageResponse.of(page, DeviceVo.class);
        return of;
    }

    @Override
    public DeviceVo selectDeviceDetail(DeviceDto deviceDto) {
        //先从数据库获取到device信息
        Device device = deviceMapper.selectDeviceByiotId(deviceDto.getIotId());
        DeviceVo deviceVo = BeanUtil.toBean(device, DeviceVo.class);

        //从阿里云获取Iot物联网设备详情数据
        QueryDeviceDetailResponse response;
        QueryDeviceDetailRequest request = new QueryDeviceDetailRequest();
        request.deviceName = device.getDeviceName();
        request.iotInstanceId = aliIOTConfigProperties.getIotInstanceId();
        request.iotId = device.getIotId();
        request.productKey = device.getProductKey();
        try {
            response = client.queryDeviceDetail(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        if (!response.body.success){
            throw new RuntimeException(response.body.errorMessage);
        }

        BeanUtil.copyProperties(response.getBody().data,deviceVo);
        return deviceVo;
    }

    @Override
    public Object queryDevicePropertyStatus(DeviceDto deviceDto) {
        QueryDevicePropertyStatusRequest request = new QueryDevicePropertyStatusRequest();
        QueryDevicePropertyStatusResponse response = null;
        request.deviceName = deviceDto.getDeviceName();
        request.iotInstanceId = aliIOTConfigProperties.getIotInstanceId();
        request.productKey = deviceDto.productKey;
        try {
            response = client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }

        if(!response.body.success){
            throw new RuntimeException(response.body.errorMessage);
        }
        return response.body.data;
    }

    @Override
    public Object queryThingModelPublished(DeviceDto deviceDto) {
        QueryThingModelPublishedResponse response = null;
        QueryThingModelPublishedRequest request = new QueryThingModelPublishedRequest();
        request.iotInstanceId = aliIOTConfigProperties.getIotInstanceId();
        request.productKey = deviceDto.productKey;
        try {
            response = client.queryThingModelPublished(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_QUERY_THING_MODEL_PUBLISHED_ERROR);
        }
        if(!response.body.success){
            throw new RuntimeException(response.body.errorMessage);
        }
        return response.body.data;
    }

    @Override
    @Transactional
    public void updateDevice(DeviceDto deviceDto) {
        //判断位置类型是否为0
        if(deviceDto.getLocationType()==0){
            deviceDto.setPhysicalLocationType(-1);
        }

        //更新数据库中的数据
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        try {
            deviceMapper.updateByPrimaryKeySelective(device);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.RE_SELECT_PRODUCT);
        }

        BatchUpdateDeviceNicknameResponse response;
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.iotInstanceId = aliIOTConfigProperties.getIotInstanceId();
        //创建infoList
        List<BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo> list = new ArrayList<>();
        //创建info对象
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo info = new BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo();
        info.deviceName = deviceDto.getDeviceName();
        info.iotId = deviceDto.getIotId();
        info.productKey = deviceDto.productKey;
        info.nickname = deviceDto.nickname;
        list.add(info);
        request.deviceNicknameInfo = list;
        try {
            response = client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            throw new BaseException(BasicEnum.IOT_BATCH_UPDATE_DEVICE_ERROR);
        }

        if(!response.body.success){
            throw new RuntimeException(response.body.errorMessage);
        }


    }

    @Override
    @Transactional
    public void deleteDevice(DeviceDto deviceDto) {
        deviceMapper.deleteByIotId(deviceDto.getIotId());
        DeleteDeviceResponse deleteDevice;
        DeleteDeviceRequest deviceRequest = new DeleteDeviceRequest();
        deviceRequest.iotId = deviceDto.getIotId();
        deviceRequest.iotInstanceId = aliIOTConfigProperties.getIotInstanceId();
        deviceRequest.productKey = deviceDto.getProductKey();
        try {
            deleteDevice = client.deleteDevice(deviceRequest);
        } catch (Exception ex) {
            throw new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
        }

        if(!deleteDevice.body.success){
            throw new RuntimeException(deleteDevice.body.errorMessage);
        }
    }

    @Override
    public Object pageQueryDeviceServiceData(Long endTime, String iotId, Integer pageSize, Long startTime) {
        QueryDeviceServiceDataResponse response = null;
        QueryDeviceServiceDataRequest request = new QueryDeviceServiceDataRequest();
        request.iotInstanceId = aliIOTConfigProperties.getIotInstanceId();
        request.iotId = iotId;
        request.endTime = endTime;
        request.pageSize = pageSize;
        request.startTime = startTime;
        try {
            response = client.queryDeviceServiceData(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return response.body.data;
    }

}
